// CSS Selector generation functions

// Generate ID-based CSS selectors
function getCssSelectorWithId(element) {
  const results = [];

  // Direct ID
  if (element.id) {
    // Simple ID selector
    results.push({
      selector: `#${element.id}`,
      description: "Using element's ID attribute",
    });

    // More specific with tag name
    results.push({
      selector: `${element.tagName.toLowerCase()}#${element.id}`,
      description: "Using element's tag name and ID attribute",
    });
  }

  // Parent with ID
  let parent = element.parentElement;
  let depth = 0;

  while (parent && parent !== document.body && depth < 3) {
    if (parent.id) {
      // Get the relative path from parent to element
      const path = getRelativeCssPathToParent(element, parent);
      results.push({
        selector: `#${parent.id} ${path}`,
        description: `Relative to parent with ID "${parent.id}"`
      });
      break;
    }
    parent = parent.parentElement;
    depth++;
  }

  parent = element.parentElement;
  if (parent && parent!== document.body) {
    const path = getRelativeCssPathToParent(element, parent.parentElement);
    results.push({
      selector: `${path}`,
      description: `Relative to parent with element "${parent.tagName.toLowerCase()}"`
    });
  }

  return results;
}

// Generate class-based CSS selectors
function getCssSelectorWithClass(element) {
  const results = [];

  if (element.className && typeof element.className === "string") {
    const classes = element.className.trim().split(/\s+/);

      // Try with multiple classes for more specificity
      const multiClassSelector = classes.map(c => `.${c}`).join('');
      results.push({
        selector: multiClassSelector,
        description: "Using multiple classes for specificity"
      });

      results.push({
        selector: `${element.tagName.toLowerCase()}${multiClassSelector}`,
        description: "Using tag name and multiple classes"
      });
    }
  

  return results;
}

// Generate attribute-based CSS selectors
function getCssSelectorWithAttributes(element) {
  const results = [];
  const excludedAttributes = [
    "id",
    "class",
    "style",
    "href",
    "target",
    "onclick",
    "src",
    "onload",
    "onunload",
    "onbeforeunload",
    "onresize",
    "onscroll",
    "onhashchange",
    "onpopstate",
    "onfocus",
    "onblur",
    "onerror",
    "onafterprint",
    "onbeforeprint",
    "onoffline",
    "ononline",
    "onchange",
    "oninput",
    "oninvalid",
    "onreset",
    "onselect",
    "onsubmit",
    "onkeydown",
    "onkeypress",
    "onkeyup",
    "ondblclick",
    "onmousedown",
    "onmousemove",
    "onmouseout",
    "onmouseover",
    "onmouseup",
    "onmousewheel",
    "onwheel",
    "oncontextmenu",
    "onabort",
    "oncanplay",
    "oncanplaythrough",
    "onended",
    "onloadeddata",
    "onloadedmetadata",
    "onloadstart",
    "onpause",
    "onplay",
    "onplaying",
    "onprogress",
    "onratechange",
    "onseeked",
    "onseeking",
    "onstalled",
    "onsuspend",
    "ontimeupdate",
    "onvolumechange",
    "onwaiting",
    "ontoggle",
    "onanimationstart",
    "onanimationend",
    "onanimationiteration",
    "ontransitionend"
  ];

  // Check all attributes
  for (let i = 0; i < element.attributes.length; i++) {
    const attr = element.attributes[i];
    // Skip id, class, style, href, target, and onclick as they're handled separately or unstable
    if (excludedAttributes.includes(attr.name)) continue;

    if (attr.value) {
      // Exact match
      results.push({
        selector: `${element.tagName.toLowerCase()}[${attr.name}="${attr.value}"]`,
        description: `Using exact "${attr.name}" attribute`
      });

      // Contains match for longer attributes
      if (attr.value.length > 10) {
        results.push({
          selector: `${element.tagName.toLowerCase()}[${attr.name}*="${attr.value.substring(0, 10)}"]`,
          description: `Using partial "${attr.name}" attribute`
        });
      }
    }
  }

  // Data attributes which are often used for testing
  for (let i = 0; i < element.attributes.length; i++) {
    const attr = element.attributes[i];
    if (attr.name.startsWith("data-")) {
      results.push({
        selector: `[${attr.name}="${attr.value}"]`,
        description: `Using "${attr.name}" data attribute`
      });
      
      results.push({
        selector: `${element.tagName.toLowerCase()}[${attr.name}="${attr.value}"]`,
        description: `Using tag and "${attr.name}" data attribute`
      });
    }
  }

  return results;
}

// Generate position-based CSS selectors
function getCssSelectorWithPosition(element) {
  const results = [];
  const tagName = element.tagName.toLowerCase();

  // Simple tag selector with nth-child
  if (element.parentElement) {
    const parent = element.parentElement;
    const children = Array.from(parent.children);
    const index = children.indexOf(element) + 1;
    
    results.push({
      selector: `${tagName}:nth-child(${index})`,
      description: `${index}${getOrdinalSuffix(index)} child of its parent`
    });

    // nth-of-type selector (more specific)
    const sameTypeSiblings = Array.from(parent.children).filter(
      child => child.tagName === element.tagName
    );
    const typeIndex = sameTypeSiblings.indexOf(element) + 1;
    
    results.push({
      selector: `${tagName}:nth-of-type(${typeIndex})`,
      description: `${typeIndex}${getOrdinalSuffix(typeIndex)} ${tagName} element among siblings`
    });

    // Parent tag + child position
    const parentTag = parent.tagName.toLowerCase();
    results.push({
      selector: `${parentTag} > ${tagName}:nth-child(${index})`,
      description: `Direct ${tagName} child of ${parentTag} element`
    });

    results.push({
      selector: `${parentTag} > ${tagName}:nth-of-type(${typeIndex})`,
      description: `Direct ${tagName} child of ${parentTag} element, ${typeIndex}${getOrdinalSuffix(typeIndex)} of its type`
    });

    // Try with parent's class if available
    if (parent.className && typeof parent.className === "string") {
      const parentClasses = parent.className.trim().split(/\s+/);
      if (parentClasses.length > 0) {
        const parentClass = parentClasses[0];
        results.push({
          selector: `.${parentClass} > ${tagName}:nth-child(${index})`,
          description: `Child of parent with class "${parentClass}"`
        });
      }
    }
  }

  // First/last/only child selectors
  if (element.parentElement) {
    const parent = element.parentElement;
    const children = Array.from(parent.children);
    
    if (children.length === 1) {
      results.push({
        selector: `${tagName}:only-child`,
        description: "Only child of its parent"
      });
    } else if (children[0] === element) {
      results.push({
        selector: `${tagName}:first-child`,
        description: "First child of its parent"
      });
    } else if (children[children.length - 1] === element) {
      results.push({
        selector: `${tagName}:last-child`,
        description: "Last child of its parent"
      });
    }

    // First/last/only of type
    const sameTypeSiblings = Array.from(parent.children).filter(
      child => child.tagName === element.tagName
    );
    
    if (sameTypeSiblings.length === 1) {
      results.push({
        selector: `${tagName}:only-of-type`,
        description: `Only ${tagName} element among siblings`
      });
    } else if (sameTypeSiblings[0] === element) {
      results.push({
        selector: `${tagName}:first-of-type`,
        description: `First ${tagName} element among siblings`
      });
    } else if (sameTypeSiblings[sameTypeSiblings.length - 1] === element) {
      results.push({
        selector: `${tagName}:last-of-type`,
        description: `Last ${tagName} element among siblings`
      });
    }
  }

  return results;
}

// Generate optimized CSS selectors
function getOptimizedCssSelectors(element) {
  const results = [];
  const tagName = element.tagName.toLowerCase();

  // Try to find unique combinations
  
  // 1. Tag + ID combinations for each class
  const result = getCssSelectorWithId(element);
  results.push(...result);

  // 2. Tag + attribute combinations
  for (let i = 0; i < element.attributes.length; i++) {
    const attr = element.attributes[i];
    if (!['id', 'class', 'style', 'href', 'target', 'onclick'].includes(attr.name)) {
      const selector = `${tagName}[${attr.name}="${attr.value}"]`;
      try {
        if (document.querySelectorAll(selector).length === 1) {
          results.push({
            selector: selector,
            description: `Unique combination of tag and ${attr.name} attribute`
          });
        }
      } catch (e) {
        // Skip invalid selectors
      }
    }
  }

  // 3. Parent context for more uniqueness
  if (element.parentElement && element.parentElement !== document.body) {
    const parent = element.parentElement;
    const parentTag = parent.tagName.toLowerCase();

    // Parent with class + child
    if (parent.className && typeof parent.className === "string") {
      const classes = parent.className.trim().split(/\s+/);
      for (const cls of classes) {
        if (cls.length > 0) {
          const selector = `.${cls} > ${tagName}`;
          try {
            if (document.querySelectorAll(selector).length === 1) {
              results.push({
                selector: selector,
                description: `Unique direct child of parent with class "${cls}"`
              });
            }
          } catch (e) {
            // Skip invalid selectors
          }
        }
      }
    }

    // Parent tag + child tag + nth-child
    const children = Array.from(parent.children);
    const index = children.indexOf(element) + 1;
    const selector = `${parentTag} > ${tagName}:nth-child(${index})`;
    try {
      if (document.querySelectorAll(selector).length === 1) {
        results.push({
          selector: selector,
          description: `Unique child position under parent tag`
        });
      }
    } catch (e) {
      // Skip invalid selectors
    }
  }

  return results;
}

// Generate absolute CSS path
function getAbsoluteCssSelector(element) {
  // Check if element is inside an iframe
  const isInIframe = isElementInIframe(element);

  // If in iframe, we need to handle differently
  if (isInIframe) {
    // For iframe elements, we can't generate a reliable CSS selector across frames
    // So we'll return a comment about this limitation
    return "/* Cannot generate cross-frame CSS selector */";
  }

  // Regular handling for elements in the main document
  if (element === document.body) {
    return "body";
  }

  return  generateAbsoluteSelector(element);
}

function generateAbsoluteSelector(element) {
  let selector = '';
  let currentElement = element;

  while (currentElement && currentElement !== document.documentElement) {
    let currentSelector = currentElement.tagName.toLowerCase();

    if (currentElement.id) {
      currentSelector += '#' + currentElement.id;
    } else if (currentElement.classList.length > 0 && currentElement !== document.body) {
      currentSelector += '.' + Array.from(currentElement.classList).join('.');
    } else {
        let childIndex = Array.from(currentElement.parentNode.children).indexOf(currentElement) + 1;
        currentSelector += `:nth-child(${childIndex})`;
    }


    selector = currentSelector + (selector ? ' > ' + selector : '');

    currentElement = currentElement.parentNode;
  }

    selector =  'html > ' + selector;
  return selector;
}

// Helper function to get relative CSS path from element to parent
function getRelativeCssPathToParent(element, parent) {
  let path = [];
  let current = element;

  while (current && current !== parent) {
    let selector = current.tagName.toLowerCase();
    
    // Add classes if available
    if (current.className && typeof current.className === "string") {
      const classes = current.className.trim().split(/\s+/).filter(c => c.length > 0);
      if (classes.length > 0) {
        selector += classes.map(c => `.${c}`).join('');
      }
    }
    
    // Add position among siblings if needed for specificity
    const currentParent = current.parentElement;
    if (currentParent) {
      const siblings = Array.from(currentParent.children).filter(
        child => child.tagName === current.tagName
      );
      
      if (siblings.length > 1) {
        const index = siblings.indexOf(current) + 1;
        selector += `:nth-of-type(${index})`;
      }
    }
    
    path.unshift(selector);
    current = current.parentElement;
  }

  return path.join(' > ');
}

// Helper function to get ordinal suffix
function getOrdinalSuffix(n) {
  const s = ["th", "st", "nd", "rd"];
  const v = n % 100;
  return s[(v - 20) % 10] || s[v] || s[0];
}

// Check if element is inside an iframe
function isElementInIframe(element) {
  try {
    return element.ownerDocument !== document;
  } catch (e) {
    return false;
  }
}